﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using aoprinter.Model;
using aoprinter.Draw;

namespace aoprinter.Core
{
    static class BlockOper
    {
        static public void InheritLocation(this ModBlock block, EnmPosition position)
        {
            if (block.Position == EnmPosition.Suspend)
            {
                block.Position = position;
            }
            if (position == EnmPosition.Absolute)
            {
                if (block.Location.X == ModBlock.ZeroPoint.X)
                {
                    block.Location = new PointF(0, block.Location.Y);
                }
                if (block.Location.Y == ModBlock.ZeroPoint.Y)
                {
                    block.Location = new PointF(block.Location.X, 0);
                }
            }
            if (block.BlockType == EnmBlockType.Case)
            {
                (block as ModCase).Blocks.ForEach(p => p.InheritLocation(block.Position));
            }
        }

        static public void AutoSizeLocation(this ModCase modCase, SizeF size, Drawer drawer)
        {
            SizeF caseSize = modCase.Size;
            if (modCase.Size.Width == ModCase.AutoSize.Width)
            {
                caseSize = new SizeF(size.Width, caseSize.Height);
            }
            if (modCase.Size.Height == ModCase.AutoSize.Height)
            {
                caseSize = new SizeF(caseSize.Width, size.Height);
            }
            modCase.Blocks.ForEach((p) => { p.AutoSizeLocation(caseSize, drawer); });

            //set relative position
            if (modCase.Position == EnmPosition.Relative)
            {
                BlockRegion blockRegion = new BlockRegion(caseSize);
                modCase.Blocks.ForEach(
                    (p) =>
                    {
                        if (p.BlockType == EnmBlockType.Delimiter)
                        {
                            p.Location = blockRegion.GetFitPosition(p.Location,
                                drawer.GetLineSize(p.Location, PointF.Add(p.Location, p.Size), (p as ModDelimiter).LineStyle),
                                p.Interval);
                        }
                        else
                        {
                            p.Location = blockRegion.GetFitPosition(p.Location, p.Size, p.Interval);
                        }
                    });
                if (modCase.Size.Height == ModCase.AutoSize.Height)
                {
                    caseSize = new SizeF(caseSize.Width, blockRegion.ParentSize.Height);
                }
            }
            modCase.Size = caseSize;
        }

        static public void AutoSizeLocation(this ModBlock block, SizeF size, Drawer drawer)
        {
            switch (block.BlockType)
            {
                case EnmBlockType.Case:
                    (block as ModCase).AutoSizeLocation(size, drawer);
                    break;
                case EnmBlockType.Text:
                    (block as ModText).AutoSizeLocation(size, drawer);
                    break;
                case EnmBlockType.Image:
                    (block as ModImage).AutoSizeLocation(size);
                    break;
                case EnmBlockType.Table:
                    (block as ModTable).AutoSizeLocation(size, drawer);
                    break;
                case EnmBlockType.Delimiter:
                    (block as ModDelimiter).AutoSizeLocation(size);
                    break;
            }
        }

        static public void Print(this ModBlock block, Drawer drawer, PointF location)
        {
            switch (block.BlockType)
            {
                case EnmBlockType.Case:
                    (block as ModCase).Print(drawer, location);
                    break;
                case EnmBlockType.Text:
                    (block as ModText).Print(drawer, location);
                    break;
                case EnmBlockType.Image:
                    (block as ModImage).Print(drawer, location);
                    break;
                case EnmBlockType.Table:
                    (block as ModTable).Print(drawer, location);
                    break;
                case EnmBlockType.Delimiter:
                    (block as ModDelimiter).Print(drawer, location);
                    break;
            }
        }

        static public void Print(this ModCase modCase, Drawer drawer, PointF location)
        {
            PointF myLocation = new PointF(location.X + modCase.Location.X, location.Y + modCase.Location.Y);
            drawer.DrawBackAndBorder(myLocation, modCase.Size, modCase.BackgroundStyle, modCase.BorderStyle);
            modCase.Blocks.ForEach(p => p.Print(drawer, PointF.Add(myLocation, new SizeF(modCase.Interval, modCase.Interval))));
        }

        static public RectangleF GetBounds(this ModBlock block)
        {
            RectangleF rect = new RectangleF(block.Location, block.Size);
            return rect;
        }
    }
}